package de.haw.gka.a1;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.AbstractGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

import org.jgrapht.graph.DirectedPseudograph;
import org.jgrapht.graph.Pseudograph;
import org.jgrapht.graph.WeightedPseudograph;


public class ReadFile {

	private static ReadFile instance;

	private ReadFile() {
	}

	public static ReadFile getInstance() {
		if (instance == null)
			instance = new ReadFile();
		return instance;
	}

	public AbstractGraph<?, ?> getGraph(String filename) {
		AbstractGraph<?, ?> tgraph = null;
		String gewichtung = "";
		try {
			List<String> fileList = read(filename);
			String titel = fileList.get(0);
           	String[] gewichtungAry = fileList.get(1).split("#");
			if (gewichtungAry.length != 1) {
				gewichtung = gewichtungAry[1];
			}

			String fristGraph = fileList.get(3);

			int GraphParamLenght = fristGraph.split(",").length;
			out("---> " + titel);
			out("---> " + gewichtung);
			out("---> " + GraphParamLenght);

			if (gewichtung.equals(gewichtet)) {
				out("gewichtet");
				tgraph = gewichtetGraph(tgraph, GraphParamLenght, titel,
						fileList);
			} else {
				out("ungewichtet");
				if (titel.equals(gerichtet)) {
					tgraph = getGerichtetGraph(fileList);
				} else if (titel.equals(ungerichtet)) {
					out("Ungerichtet");
					tgraph = getUngerichtetGraph(fileList);
				} else {
					throw new IllegalArgumentException("Wrong File");
				}
			}			
		} catch (FileNotFoundException e) {
            e.printStackTrace();
			JOptionPane.showMessageDialog(null, "Fehler beim Laden!\n" + filename,"FileNotFound...", JOptionPane.ERROR_MESSAGE);
		} 
		catch (IOException e) {	
			JOptionPane.showMessageDialog(null, "Fehler beim Laden!","IOException...", JOptionPane.ERROR_MESSAGE);
		}
		return tgraph;
	}

	public int getAnzahlEcken() {
		return anzahlE;
	}

	// /////////////////////////////
	// Graphen
	// ///////////////////

	private AbstractGraph<?, ?> gewichtetGraph(AbstractGraph<?, ?> aGraph,
			int paramLenght, String typ, List<String> fileList) {
		if (paramLenght != 3) {
			out("Attributiert");
			aGraph = attributierterGraph(aGraph, fileList, typ);
		} else {
			out("Unattributiert");
			aGraph = unattributierterGraph(aGraph, typ, fileList);
		}
		return aGraph;
	}

	private AbstractGraph<String, DefaultWeightedEdge> unattributierterGraph(
			AbstractGraph<?, ?> aGraph, String typ, List<String> fileList) {
		if (typ.equals(gerichtet)) {
			out("Gerichtet");
			aGraph = getGewichtetGerichtetGraphWithOutParams(fileList);
		} else if (typ.equals(ungerichtet)) {
			out("Ungerichtet");
			aGraph = getGewichtetUngerichtetGraphWithOutParams(fileList);
		} else {
			throw new IllegalArgumentException("Wrong File");
		}
		return (AbstractGraph<String, DefaultWeightedEdge>) aGraph;
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> attributierterGraph(
			AbstractGraph<?, ?> aGraph, List<String> fileList, String typ) {
		if (typ.equals(gerichtet)) {
			out("Gerichtet");
			aGraph = getGewichtetGerichtetGraph(fileList);
		} else if (typ.equals(ungerichtet)) {
			out("Ungerichtet");
			aGraph = getGewichtetUngerichtetGraph(fileList);
		} else {
			throw new IllegalArgumentException("Wrong File");
		}
		return (AbstractGraph<Knoten, DefaultWeightedEdge>) aGraph;
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> getGewichtetUngerichtetGraphWithOutParams(List<String> file) {
		AbstractGraph<Knoten, DefaultWeightedEdge> graph = new WeightedPseudograph<Knoten, DefaultWeightedEdge>(DefaultWeightedEdge.class);
		return fillGewichtetGraphWithOutParams(file, graph);
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> getGewichtetGerichtetGraphWithOutParams(List<String> file) {
		AbstractGraph<Knoten, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<Knoten, DefaultWeightedEdge>(DefaultWeightedEdge.class);
		return fillGewichtetGraphWithOutParams(file, graph);
	}

	private AbstractGraph<String, DefaultEdge> getGerichtetGraph(List<String> filename) {
		AbstractGraph<String, DefaultEdge> graph = new DirectedPseudograph<String, DefaultEdge>(DefaultEdge.class);
		return fillUngewichtetGraph(filename, graph);
	}

	private AbstractGraph<String, DefaultEdge> getUngerichtetGraph(List<String> filename) {
		AbstractGraph<String, DefaultEdge> graph = new Pseudograph<String, DefaultEdge>(DefaultEdge.class);
		return fillUngewichtetGraph(filename, graph);
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> getGewichtetUngerichtetGraph(List<String> filename) {
		AbstractGraph<Knoten, DefaultWeightedEdge> graph = new WeightedPseudograph<Knoten, DefaultWeightedEdge>(DefaultWeightedEdge.class);
		return fillGewichtetGraph(filename, graph);
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> getGewichtetGerichtetGraph(List<String> filename) {
		AbstractGraph<Knoten, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<Knoten, DefaultWeightedEdge>(DefaultWeightedEdge.class);
		return fillGewichtetGraph(filename, graph);
	}

	// ////////////////////////
	// Graph befuellen
	// ///////////////////

	private AbstractGraph<String, DefaultEdge> fillUngewichtetGraph(List<String> fileList, AbstractGraph<String, DefaultEdge> graph) {
		anzahlE = 0;
		for (int i = 1; i < fileList.size(); i++) {
			String zeile = fileList.get(i);
			String[] parts = zeile.split(","); // Array Initialisieren, mit
												// Strings der jeweiligen Zeile
												// faellen (getrennt durch ",")
			if (parts.length == 2) {
				if (!graph.containsVertex(parts[0])) { // Ueberpruefen ob der
														// Graph die erste Ecke
														// die ausgelesen wurde
														// schon enthaellt
					graph.addVertex(parts[0]); // falls nicht, Ecke dem Graphen
												// hinzufuegen

					anzahlE++;
				}
				if (!graph.containsVertex(parts[1])) { // Aeberpruefen ob der
														// Graph die zweite Ecke
														// die ausgelesen wurde
														// schon enthaellt
					graph.addVertex(parts[1]); // falls nicht, Ecke dem Graphen
												// hinzufuegen
					anzahlE++;
				}
				graph.addEdge(parts[0], parts[1]);
			}
		}
		return graph;
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> fillGewichtetGraphWithOutParams(List<String> fileList,
			AbstractGraph<Knoten, DefaultWeightedEdge> graph) {
		anzahlE = 0;
		for (int i = 1; i < fileList.size(); i++) {
			String zeile = fileList.get(i);
			String[] parts = zeile.split(","); // Array Initialisieren, mit
												// Strings der jeweiligen Zeile
												// faellen (getrennt durch ",")
			if (parts.length == 3) {
                Knoten a = new Knoten(parts[0]);
				if (!graph.containsVertex(a)) { // Ueberpruefen ob der
														// Graph die erste Ecke
														// die ausgelesen wurde
														// schon enthaellt
					graph.addVertex(a); // falls nicht, Ecke dem Graphen
												// hinzufuegen
					anzahlE++;
				}
                Knoten b = new Knoten(parts[1]);
				if (!graph.containsVertex(b)) { // Aeberpruefen ob der
														// Graph die zweite Ecke
														// die ausgelesen wurde
														// schon enthaellt
					graph.addVertex(new Knoten(parts[1])); // falls nicht, Ecke dem Graphen
												// hinzufuegen
					anzahlE++;
				}
				DefaultWeightedEdge de = graph.addEdge(a, b);
				if (graph instanceof WeightedPseudograph) {
					((WeightedPseudograph<Knoten, DefaultWeightedEdge>) graph).setEdgeWeight(de, Double.valueOf(parts[2]).doubleValue());

				} else if (graph instanceof DefaultDirectedWeightedGraph) {
					((DefaultDirectedWeightedGraph<Knoten, DefaultWeightedEdge>) graph)
							.setEdgeWeight(de, Double.valueOf(parts[2])
									.doubleValue());
				}
			}
		}
		return graph;
	}

	private AbstractGraph<Knoten, DefaultWeightedEdge> fillGewichtetGraph(
			List<String> fileList,
			AbstractGraph<Knoten, DefaultWeightedEdge> graph) {
		anzahlE = 0;
		Knoten a, b;
		for (int i = 1; i < fileList.size(); i++) {
			String zeile = fileList.get(i);
			String[] parts = zeile.split(","); // Array Initialisieren, mit
												// Strings der jeweiligen Zeile
												// faellen (getrennt durch ",")
			if (parts.length == 5) {
				a = new Knoten(parts[0], Integer.valueOf(parts[1].replaceAll(" ", "")).intValue());
				if (!graph.containsVertex(a)) { // Ueberpruefen ob der Graph die
												// erste Ecke die ausgelesen
												// wurde schon enthaellt
					graph.addVertex(a); // falls nicht, Ecke dem Graphen
										// hinzufuegen
					anzahlE++;
				}
				b = new Knoten(parts[2], Integer.valueOf(parts[3].replaceAll(" ", " ")).intValue());
				if (!graph.containsVertex(b)) { // Aeberpruefen ob der Graph die
												// zweite Ecke die ausgelesen
												// wurde schon enthaellt
					graph.addVertex(b); // falls nicht, Ecke dem Graphen
										// hinzufuegen
					anzahlE++;
				}
				DefaultWeightedEdge de = graph.addEdge(a, b);

				if (graph instanceof WeightedPseudograph) {
					((WeightedPseudograph<Knoten, DefaultWeightedEdge>) graph).setEdgeWeight(de, Double.valueOf(parts[4]).doubleValue());
				} else if (graph instanceof DefaultDirectedWeightedGraph) {
					((DefaultDirectedWeightedGraph<Knoten, DefaultWeightedEdge>) graph).setEdgeWeight(de, Double.valueOf(parts[4]).doubleValue());
				}
			}
		}
		return graph;
	}

	// Ausgabe //


	private void out(String tmp) {
		System.out.println(tmp);
	}

	////////////////
	// Datei einlesen
	////////////

	private List<String> read(String filename) throws IOException {
		FileReader fr = new FileReader(filename);
		List<String> result = new ArrayList<String>();
		BufferedReader br = new BufferedReader(fr);
		String zeile;
		while ((zeile = br.readLine()) != null) {
			result.add(zeile);
        }
		return result;
	}

	private int anzahlE;
	private String gerichtet = "#gerichtet";
	private String ungerichtet = "#ungerichtet";
	private String gewichtet = "gewichtet";

}
